#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h> // variable argument lists
#include <string.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <syslog.h>
#include "ipcd.h"

/** ISSUES
- Handle TTY signals!!
- Close all file descriptors then connect stdin, stdout, stderr to /dev/null
- Remove unnecessary header files!!
*/

void log_message(char *filename, const char* format, ...) {
	FILE *logfile;
	logfile = fopen(filename, "a");
	if (!logfile) return;
	va_list list;
	va_start( list, format );
	vfprintf(logfile, format, list);
	va_end( list );
	fprintf(logfile, "\n");
    	fclose(logfile);
}


double fibonacci(int n) {
    
    double a = 1;
    double b = 1;
    double sum;
    int i;

    if(n==0) {return 0;}
    else if(n==1 || n==2) {return 1;}
    else {
    	for (i=3; i<=n; i++) {
	
    		sum = a + b;
    		a = b;
    		b = sum;
    	}

    	return sum;
    }
}


int main(int argc, char *argv[]) {

 	key_t  key;   /* key to be passed to shmget() */
 	int  shmid;   /* return value from shmget() */

 	shmseg_t *shm;
 	sem_t *signal_in, *signal_out;
 
	char * tmpdir = (char *) malloc(sizeof(char)*1024);
	strcat(tmpdir,"/tmp/");
	strcat(tmpdir,getenv("USERNAME"));

        /* Our process ID and Session ID */
        pid_t pid, sid;
        char  *fname = {0};
	
        //time_t seconds,ref;
        fname =(char *)malloc((strlen("logtest")+1)*sizeof(char));
        strcpy(fname,"logtest");
	
        /* Fork off the parent process */
        pid = fork();
	
        if (pid < 0) {
                exit(EXIT_FAILURE);
        }
        /* If we got a good PID, then
           we can exit the parent process. */
        if (pid > 0) {
                exit(EXIT_SUCCESS);
        }

        /* Change the file mode mask */
        umask(0);
                                
        /* Create a new SID for the child process */
        sid = setsid();
        if (sid < 0) {
                exit(EXIT_FAILURE);
        }
        
        
        /* Change the current working directory */
        if ((chdir(tmpdir)) < 0) {
		log_message(fname ,"not op.. error ");
                exit(EXIT_FAILURE);
        }
        
        /* Close out the standard file descriptors */
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
        open("/dev/null", O_RDONLY);
        open("/dev/null", O_RDWR);
        open("/dev/null", O_RDWR);

	//remove existing semaphores initially at server startup
    	sem_unlink(SEMAPHORE_INPUT);
    	sem_unlink(SEMAPHORE_OUTPUT);
	sem_unlink(SEMAPHORE_CHILD);
//------------------------------------------------------------------------------------------

        key = 69; //shared memory segment key

     	/* Create the segment.*/
        if ((shmid = shmget(key, sizeof(shmseg_t), IPC_CREAT | 0666)) < 0) {
            log_message(fname ,"shmget1.. error ");
            exit(1);
        }

        /* Attach the segment to address space of daemon. */
        if ((shm = shmat(shmid, NULL, 0)) == (shmseg_t *) -1) {
            log_message(fname ,"shmmat.. error ");
            exit(1);
        }

        if ( (signal_in = sem_open(SEMAPHORE_INPUT, O_CREAT | O_EXCL, 0666,0)) == SEM_FAILED ){
        	log_message(fname ,"Error sem_open");
        	exit(1);
        }
	
        if ( (signal_out = sem_open(SEMAPHORE_OUTPUT, O_CREAT | O_EXCL, 0666,0)) == SEM_FAILED ){
        	log_message(fname ,"Error sem_open");
        	exit(1);
        }


        while (1){
        	  if ( sem_wait(signal_in)==-1) {     
		      log_message(fname ,"Error sem_wait..");
        	      exit(1);
        	  }

                  log_message(fname ,"input data received, n =%d", shm->n);
              	  shm->fibonacci = fibonacci(shm->n);
	      	  sleep(2);
              	  log_message(fname,"result fibonacci =%f", shm->fibonacci);
              	  sem_post(signal_out);
              	  log_message(fname,"semaphore wait n");
        }


    //code never reaches here!!
    sem_close(signal_in);
    sem_close(signal_out);
    sem_unlink(SEMAPHORE_INPUT);
    sem_unlink(SEMAPHORE_OUTPUT);
   
    exit(EXIT_SUCCESS);
}




